﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Reflection;
using System.ComponentModel;
using Winforms = System.Windows.Forms;
using Microsoft.Xna.Framework;
namespace SmokinAces
{
    /// <summary>
    /// This Class contains all of the things in the game.
    /// </summary>
    public abstract class Game_Object
    {
        protected Main_Engine parent;
        public Game_Object()
        {
        }
        public Game_Object(XmlReader xmlReader, Main_Engine Parent)
        {
            //what now
        }
        public Game_Object(int Left, int Top, Main_Engine Parent)
        {
            parent = Parent;
            GraphicBB = new BoundingBox(new Vector3(Left, Top,-100.0f),new Vector3(Left + 8, Top + 8, 100.0f));
        }
        virtual public bool Save_XML(XmlTextWriter textWriter)
        {
            try
            {
                textWriter.WriteStartElement("Game_Object");
                textWriter.WriteAttributeString("Type", this.GetType().AssemblyQualifiedName);
                textWriter.WriteEndElement();
            }
            catch
            {
                return false;
            }
            return true;
        }
        public static Game_Object Load_XML(XmlTextReader textReader, Main_Engine Parent)
        {
            Game_Object output = null;
            
            try
            {
                textReader.ReadToFollowing("Game_Object");
                textReader.MoveToAttribute("Type");
                textReader.ReadAttributeValue();
                String typedata = textReader.ReadContentAsString();
                Type newType = Type.GetType(typedata);
                Type[] constParams = {typeof(XmlTextReader),typeof(Main_Engine) };
                ConstructorInfo builder = newType.GetConstructor(constParams);
                if (builder != null)
                {
                    Object[] parmset = { (textReader), (Parent) };
                    output = (Game_Object)builder.Invoke(parmset);
                }
            }
            catch
            {
                return null;
            }
            return output;
        }
        public BoundingBox GraphicBB;
		public Vector2 ReferencePoint
		{
			get { return new Vector2(GraphicBB.Min.X, GraphicBB.Min.Y); }
		}
        public List<BoundingBox> Bounding_Regions = new List<BoundingBox>();
        public List<BoundingBox> Bounding_Armor = new List<BoundingBox>();
        public List<BoundingBox> Bounding_Weapon = new List<BoundingBox>();
        public abstract bool dispose();
        static Type[] constructor_parameters = { typeof(int), typeof(int), typeof(Main_Engine) };
        static object[] default_const_values = { 0, 0, null };

        public void updateBoundingRegions(Vector3 Direction)
        {
            GraphicBB.Min += Direction;
            GraphicBB.Max += Direction;
            List<BoundingBox> BoundingList = new List<BoundingBox>();
            for (int i = 0; i < Bounding_Regions.Count; i++)
            {
                BoundingList.Add(new BoundingBox(Bounding_Regions[i].Min + Direction, Bounding_Regions[i].Max + Direction));
            }
            Bounding_Regions = BoundingList;
            //----Weapon Region
            List<BoundingBox> BoundingWeaponList = new List<BoundingBox>();
            for (int i = 0; i < Bounding_Weapon.Count; i++)
            {
                BoundingWeaponList.Add(new BoundingBox(Bounding_Weapon[i].Min + Direction, Bounding_Weapon[i].Max + Direction));
            }
            Bounding_Weapon = BoundingWeaponList;
        }
        public bool isColliding()
        {
            HashSet<Game_Object> Possible_Collisions = parent.MapObjects.Intersections(GraphicBB);
            Possible_Collisions.Add((parent as Game_Engine).Hero);
            Possible_Collisions.Remove(this);
            foreach (Game_Object PossibleGO in Possible_Collisions)
            {

                foreach (BoundingBox PossibleBB in PossibleGO.Bounding_Regions)
                {
                    foreach (BoundingBox PossibleBBME in this.Bounding_Regions)
                    {
                        if (PossibleBB.Intersects(PossibleBBME))
                        {
                            return true;
                        }
                    }
                    foreach (BoundingBox PossibleBBME in this.Bounding_Weapon)
                    {
                        if (PossibleBB.Intersects(PossibleBBME))
                        {
                            return true;
                        }
                    }
                    foreach (BoundingBox PossibleBBME in this.Bounding_Armor)
                    {
                        if (PossibleBB.Intersects(PossibleBBME))
                        {
                            return true;
                        }
                    }
                }
                foreach (BoundingBox PossibleBB in PossibleGO.Bounding_Weapon)
                {
                    foreach (BoundingBox PossibleBBME in this.Bounding_Regions)
                    {
                        if (PossibleBB.Intersects(PossibleBBME))
                        {
                            return true;
                        }
                    }
                    foreach (BoundingBox PossibleBBME in this.Bounding_Weapon)
                    {
                        if (PossibleBB.Intersects(PossibleBBME))
                        {
                            return true;
                        }
                    }
                    foreach (BoundingBox PossibleBBME in this.Bounding_Armor)
                    {
                        if (PossibleBB.Intersects(PossibleBBME))
                        {
                            return true;
                        }
                    }
                }
                foreach (BoundingBox PossibleBB in PossibleGO.Bounding_Armor)
                {
                    foreach (BoundingBox PossibleBBME in this.Bounding_Regions)
                    {
                        if (PossibleBB.Intersects(PossibleBBME))
                        {
                            return true;
                        }
                    }
                    foreach (BoundingBox PossibleBBME in this.Bounding_Weapon)
                    {
                        if (PossibleBB.Intersects(PossibleBBME))
                        {
                            return true;
                        }
                    }
                    foreach (BoundingBox PossibleBBME in this.Bounding_Armor)
                    {
                        if (PossibleBB.Intersects(PossibleBBME))
                        {
                            return true;
                        }
                    }
                }
            }
            return false;
        }
        //-----------Pass in the object a bounding box that will test against
        //-----------all the nearby game objects for a collision
        //-----------this object isn't added to the collision
        public HashSet<Game_Object> isCollidingWith(BoundingBox Bounds, Collision_Type Ctype)
        {
            HashSet<Game_Object> Possible_Collisions = parent.MapObjects.Intersections(Bounds);
            HashSet<Game_Object> Collisions = new HashSet<Game_Object>();
            
            Possible_Collisions.Add((parent as Game_Engine).Hero);
            Possible_Collisions.Remove(this);
            switch (Ctype)
            {
                case Collision_Type.BoundingVolume:
                    foreach (Game_Object PossibleGO in Possible_Collisions)
                    {
                            //-----------------You want to check against the Bounding_Regions
                            foreach (BoundingBox PossibleBB in PossibleGO.Bounding_Regions)
                            {
                                if (PossibleBB.Intersects(Bounds))
                                {
                                    Collisions.Add(PossibleGO);
                                    break;
                                }
                            }
                    }
                    break;
                case Collision_Type.Armor:
                    foreach (Game_Object PossibleGO in Possible_Collisions)
                    {
                            //-----------------You want to check against the Bounding_Armor
                            foreach (BoundingBox PossibleBB in PossibleGO.Bounding_Armor)
                            {
                                if (PossibleBB.Intersects(Bounds))
                                {
                                    Collisions.Add(PossibleGO);
                                    break;
                                }
                            }
                    }
                    break;
                case Collision_Type.Weapon:
                    foreach (Game_Object PossibleGO in Possible_Collisions)
                    {

                            //-----------------You want to check against the Bounding_Weapon
                            foreach (BoundingBox PossibleBB in PossibleGO.Bounding_Weapon)
                            {
                                if (PossibleBB.Intersects(Bounds))
                                {
                                    Collisions.Add(PossibleGO);
                                    break;
                                }
                            }

                    }
                    break;
            }
            return Collisions;
        }
    }
    public enum Collision_Type
    {
        Armor,
        Weapon,
        BoundingVolume
    }

    /*
	public abstract class Bounding_Region
	{
		public struct Intersection
		{
			public Game_Object Subject;
			public Game_Object Object;
			public Class ObjectClass;
			public Class SubjectClass;

			public bool IsCollision
			{
				get
				{
					return (ObjectClass == Class.LowerCollision && SubjectClass == Class.LowerCollision) ||
						(ObjectClass == Class.UpperCollision && SubjectClass == Class.UpperCollision);
				}
			}
			public bool IsDamageInflicted
			{
				get
				{
					return ((ObjectClass == Class.AttackPoint || ObjectClass == Class.AttackRegion) &&
						(SubjectClass == Class.SensitivePoint || SubjectClass == Class.SensitiveRegion));
				}
			}
		}
		public enum Class { LowerCollision, UpperCollision, SensitiveRegion, SensitivePoint, AttackRegion, AttackPoint }
		public static IEnumerable<Intersection> GetIntersections(Game_Object a, Game_Object b)
		{
			if(object.ReferenceEquals(a, b)) return new Intersection[] { };
			return from ar in a.Bounding_Regions
				   join br in b.Bounding_Regions on true equals true
				   where ar.Intersects(br) select new Intersection
					{
						Object = b,
						Subject = a,
						ObjectClass = br.BoundingClass,
						SubjectClass = ar.BoundingClass
					};
		}

		public Game_Object Parent { get; private set; }
		public Class BoundingClass { get; private set; }

		protected Bounding_Region(Game_Object gameObj, Class boundingClass)
		{
			BoundingClass = boundingClass;
			Parent = gameObj;
		}
		public abstract bool Intersects(Bounding_Region other);
	}
	public sealed class Point_Region : Bounding_Region
	{
		public Vector2 Point { get; private set; }
		public Vector2 GetGlobalPoint()
		{
			return Point + Parent.ReferencePoint;
		}
		public Point_Region(Game_Object gameObj, Vector2 point, Class boundingClass)
			: base(gameObj, boundingClass)
		{
			Point = point;
		}
		public override bool Intersects(Bounding_Region other)
		{
			if(other is Box_Region) return other.Intersects(this);
			else if(other is Point_Region)
			{
				var p = (other as Point_Region).GetGlobalPoint();
				var t = this.GetGlobalPoint();
				float dx = Math.Abs(p.X - t.X);
				float dy = Math.Abs(p.Y - t.Y);

				if((dx + dy) < (32f * float.Epsilon))
					return true;
				else
					return false;
			}
			return false;
		}
	}
	public sealed class Box_Region : Bounding_Region
	{
		public Vector2 Max { get; private set; }
		public Vector2 Min { get; private set; }
		public Box_Region(Game_Object gameObj, BoundingBox box, Class boundingClass)
			: base(gameObj, boundingClass)
		{
			Max = new Vector2(box.Max.X, box.Max.Y);
			Min = new Vector2(box.Min.X, box.Min.Y);
		}
		public Box_Region(Game_Object gameObj, Vector2 mn, Vector2 mx, Class boundingClass)
			: base(gameObj, boundingClass)
		{
			Max = mx;
			Min = mn;
		}
		public override bool Intersects(Bounding_Region other)
		{
			Func<Vector2, Box_Region, bool> boxed = (v, r) =>
				(v.X <= r.GlobalMax.X && v.X >= r.GlobalMin.X) && (v.Y <= r.GlobalMax.Y && v.Y >= r.GlobalMin.Y);
			if(other is Point_Region)
			{
				var p = other as Point_Region;
				return boxed(p.GetGlobalPoint(), this);
			}
			else if(other is Box_Region)
			{
				var r = other as Box_Region;
				return GetGlobalPoints().Any(v => boxed(v, r));
			}
			return false;
		}

		public IEnumerable<Vector2> GetGlobalPoints()
		{
			yield return Min + Parent.ReferencePoint;
			yield return Max + Parent.ReferencePoint;
			yield return new Vector2(Max.X, Min.Y) + Parent.ReferencePoint;
			yield return new Vector2(Min.X, Max.Y) + Parent.ReferencePoint;
		}
		public Vector2 GlobalMax { get { return Max + Parent.ReferencePoint; } }
		public Vector2 GlobalMin { get { return Min + Parent.ReferencePoint; } }
	}

    
     */
}
